from collections import defaultdict
from django.db.models import Count, Avg
from content.models import Goods, UserShopping, UserRating
from login.models import User


class Recommender:
    def __init__(self):
        self.user_prefs = defaultdict(dict)  # 用户偏好 {user_id: {category: weight}}
        self.goods_features = {}  # 商品特征 {goods_id: (category, price, rating)}

    def load_data(self):
        """加载基础数据"""
        # 商品特征（分类、价格、评分）
        for goods in Goods.objects.all():
            avg_rating = goods.userrating_set.aggregate(Avg('rating'))['rating__avg'] or 3.0
            self.goods_features[goods.id] = (
                goods.category,
                float(goods.price) if goods.price else 0.0,
                avg_rating
            )

        # 用户偏好（基于购买记录）
        for user in User.objects.all():
            purchases = UserShopping.objects.filter(user=user).values_list('goods__category', flat=True)
            category_counts = defaultdict(int)
            for cat in purchases:
                if cat: category_counts[cat] += 1
            total = sum(category_counts.values()) or 1
            self.user_prefs[user.id] = {cat: count / total for cat, count in category_counts.items()}

    def recommend(self, user_id, top_n=5):
        """生成推荐"""
        # 获取用户偏好
        user_cats = self.user_prefs.get(user_id, {})

        # 已购买商品
        bought = set(UserShopping.objects.filter(user_id=user_id).values_list('goods_id', flat=True))

        # 候选商品排序规则
        candidates = []
        for gid, (cat, price, rating) in self.goods_features.items():
            if gid in bought:
                continue

            # 简单评分规则：分类匹配 + 价格优惠 + 高评分
            score = (
                    user_cats.get(cat, 0) * 0.5 +  # 分类权重
                    (1 - price / 1000) * 0.3 +  # 低价权重（假设最高价1000）
                    (rating / 5) * 0.2  # 评分权重
            )
            candidates.append((gid, score))

        # 排序取前N
        candidates.sort(key=lambda x: -x[1])

        # 如果结果不足，补充热门商品
        if len(candidates) < top_n:
            hot_goods = Goods.objects.annotate(
                purchase_count=Count('usershopping')
            ).order_by('-purchase_count')[:top_n]
            hot_ids = [(g.id, 0.0) for g in hot_goods]
            candidates = list(set(candidates + hot_ids))[:top_n]

        return [gid for gid, _ in candidates[:top_n]]

    def update_user(self, user_id):
        """更新单个用户数据"""
        purchases = UserShopping.objects.filter(user_id=user_id).values_list('goods__category', flat=True)
        category_counts = defaultdict(int)
        for cat in purchases:
            if cat: category_counts[cat] += 1
        total = sum(category_counts.values()) or 1
        self.user_prefs[user_id] = {cat: count / total for cat, count in category_counts.items()}


